package com.zpb.framework.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zpb.framework.domain.ApiResult;
import com.zpb.framework.domain.dto.ArticleAddDto;
import com.zpb.framework.domain.dto.ArticleEditDto;
import com.zpb.framework.domain.dto.ArticleQueryDto;
import com.zpb.framework.domain.entity.Article;
import com.zpb.framework.domain.entity.ArticleDetailVo;
import com.zpb.framework.domain.entity.Category;
import com.zpb.framework.domain.enums.ResultCodeEnum;
import com.zpb.framework.domain.vo.ArticleBriefVo;
import com.zpb.framework.domain.vo.ArticleEditVo;
import com.zpb.framework.domain.vo.HotArticleVo;
import com.zpb.framework.domain.vo.PageVo;
import com.zpb.framework.mapper.ArticleMapper;
import com.zpb.framework.mapper.CategoryMapper;
import com.zpb.framework.service.ArticleService;
import com.zpb.framework.utils.BeanCopyUtil;
import com.zpb.framework.utils.DictCodeUtil;
import com.zpb.framework.utils.NumConst;
import com.zpb.framework.utils.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: zhaopengbo
 * @Date: 2025/9/7
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public ApiResult<List<HotArticleVo>> getHotArticleList() {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getViewCount)
                .eq(Article::getDelFlag, NumConst.ZERO) //配置中已进行配置，可以不写
                .eq(Article::getStatus, NumConst.ZERO)
                .last("limit 10");
        List<Article> articles = articleMapper.selectList(queryWrapper);
//        List<HotArticleVo> hotArticleVos = new ArrayList<>();
//        articles.forEach(article -> {
//            HotArticleVo hotArticleVo = BeanCopyUtil.copyBean(article, HotArticleVo.class);
//            hotArticleVos.add(hotArticleVo);
//        });
        List<HotArticleVo> hotArticleVos = BeanCopyUtil.copyBeanList(articles, HotArticleVo.class);
        return ApiResult.success(hotArticleVos);

    }

    @Override
    public ApiResult<PageVo> getListByCondition(Integer pageNum, Integer pageSize, Article article) {
        // 根据条件分页查询文章
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>(article);
        queryWrapper.orderByDesc(Article::getIsTop)
                .eq(Article::getDelFlag, NumConst.ZERO)
                .eq(Article::getStatus, NumConst.ZERO);
        Page<Article> articlePage = new Page<>(pageNum, pageSize);
        page(articlePage, queryWrapper);
        List<Article> articleList = articlePage.getRecords();

        articleList.forEach(a -> {
            Integer cacheMapValue = (Integer) redisCache.getCacheMapValue("article:viewCount", a.getId().toString());
            a.setViewCount(cacheMapValue.longValue());
        });
        //创建查询到的文章id列表，根据id查询分类列表
        Set<Long> categoryIds = articleList.stream()
                .map(Article::getCategoryId)
                .collect(Collectors.toSet());
        List<Category> categoryList = categoryMapper.selectBatchIds(categoryIds);

        //避免多次查询数据库，将查询到的分类列表id和name分装到map中
        Map<Long, String> categoryMap = new HashMap<>();
        categoryList
                .forEach(category -> {
                    categoryMap.put(category.getId(), category.getName());
                });

        //进行bean拷贝，categoryName字段通过map进行赋值
        List<ArticleBriefVo> articleBriefVoList = new ArrayList<>();
        articleList.stream()
                .forEach(a -> {
                    ArticleBriefVo articleBriefVo = BeanCopyUtil.copyBean(a, ArticleBriefVo.class);
                    articleBriefVo.setCategoryName(categoryMap.get(a.getCategoryId()));
                    articleBriefVoList.add(articleBriefVo);
                });

        PageVo pageVo = new PageVo(articlePage.getTotal(), articleBriefVoList);
        return ApiResult.success(pageVo);
    }

    @Override
    public ApiResult<ArticleDetailVo> getDetailById(Long id) {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Article::getStatus, NumConst.ZERO)
                .eq(Article::getDelFlag, NumConst.ZERO)
                .eq(Article::getId, id);

        Article article = articleMapper.selectOne(wrapper);

        if (article == null || ObjectUtils.isEmpty(article)) {
            return ApiResult.failure(ResultCodeEnum.NO_ARTICLE);
        }

        Integer cacheMapValue = (Integer) redisCache.getCacheMapValue("article:viewCount", article.getId().toString());
        article.setViewCount(cacheMapValue.longValue());
        ArticleDetailVo articleDetailVo = BeanCopyUtil.copyBean(article, ArticleDetailVo.class);
        articleDetailVo.setCategoryName(categoryMapper.selectById(article.getCategoryId()).getName());

        return ApiResult.success(articleDetailVo);

    }

    @Override
//    public ApiResult addViewCount(Long articleId) {
//        Article article = articleMapper.selectById(articleId);
//        if (article == null || ObjectUtils.isEmpty(article)) {
//            return ApiResult.failure(ResultCodeEnum.NO_ARTICLE);
//        }
//        article.setViewCount(article.getViewCount()+1);
//        articleMapper.updateById(article);
//        return null;
//    }
    public ApiResult addViewCount(Long articleId) {
        redisCache.setCacheSet("article:viewCount:updated", articleId);
        Long count = redisCache.incrementCacheMapValue("article:viewCount", articleId.toString());

        return ApiResult.success(count);
    }

    @Transactional
    @Override
    public ApiResult addArticle(ArticleAddDto articleAddDto) {
        Article article = BeanCopyUtil.copyBean(articleAddDto, Article.class);
        int result = articleMapper.insert(article);

        if (result > 0) {
            List<Long> tags = articleAddDto.getTags();
            int tagResult = articleMapper.insertArticleTag(article.getId(), tags);
            if (tagResult > 0) {
                return ApiResult.success();
            }

        }
        return ApiResult.failure(ResultCodeEnum.ADD_FAILURE);
    }

    @Override
    public ApiResult<PageVo> getArticleListByCondition(Integer pageNum, Integer pageSize, ArticleQueryDto articleQueryDto) {
//        Article query = BeanCopyUtil.copyBean(articleQueryDto, Article.class);
        Page<Article> articlePage = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(articleQueryDto.getTitle() != null, Article::getTitle, articleQueryDto.getTitle())
                .like(articleQueryDto.getSummary() != null, Article::getSummary, articleQueryDto.getSummary())
                .eq(Article::getStatus, DictCodeUtil.NO_DELETE)
                .orderByDesc(Article::getIsTop)
                .orderByDesc(Article::getCreateTime)
                .orderByDesc(Article::getId);
        page(articlePage, queryWrapper);
        List<Article> articleList = articlePage.getRecords();
        Set<Long> categoryIds = articleList.stream()
                .map(Article::getCategoryId)
                .collect(Collectors.toSet());
        List<Category> categoryList = categoryMapper.selectBatchIds(categoryIds);
        Map<Long, String> categoryMap = new HashMap<>();
        categoryList.forEach(c -> {
            categoryMap.put(c.getId(), c.getName());
        });
        List<ArticleDetailVo> articleDetailVos = new ArrayList<>();
        articleList.stream()
                .forEach(a -> {
                    ArticleDetailVo articleDetailVo = BeanCopyUtil.copyBean(a, ArticleDetailVo.class);
                    articleDetailVo.setCategoryName(categoryMap.get(a.getCategoryId()));
                    articleDetailVos.add(articleDetailVo);
                });
        PageVo pageVo = new PageVo(articlePage.getTotal(), articleDetailVos);
        return ApiResult.success(pageVo);
    }

    @Override
    public ApiResult<ArticleEditVo> getArticleById(Long id) {
        Article article = articleMapper.selectById(id);
        if (article == null || ObjectUtils.isEmpty(article)) {
            return ApiResult.failure(ResultCodeEnum.NO_ARTICLE);
        }
        ArticleEditVo articleEditVo = BeanCopyUtil.copyBean(article, ArticleEditVo.class);
        List<Long> tagIds = articleMapper.selectTagIdsByArticleId(article.getId());
        articleEditVo.setTags(tagIds);
        return ApiResult.success(articleEditVo);
    }

    @Override
    @Transactional
    public ApiResult updateArticleById(ArticleEditDto articleEditDto) {
        Article article = BeanCopyUtil.copyBean(articleEditDto, Article.class);
        int articleResult = articleMapper.updateById(article);
        if (articleResult > 0) {
            int tagResult = articleMapper.deleteArticleTagByArticleId(article.getId());
            List<Long> tagIds = articleEditDto.getTags();
            int result = articleMapper.insertArticleTag(article.getId(), tagIds);
            if (result > 0) {
                return ApiResult.success();
            }
        }
        return ApiResult.failure(ResultCodeEnum.UPDATE_FAILURE);
    }

    @Override
    @Transactional
    public ApiResult deleteArticleById(Long id) {
        int delResult = articleMapper.deleteById(id);
        if (delResult > 0) {
            int tagResult = articleMapper.deleteArticleTagByArticleId(id);
            return ApiResult.success();
        }
        return ApiResult.error(ResultCodeEnum.DEL_FAILURE);
    }
}
